﻿using HamcoWcs.Entitys.Logss;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.DeviceMsgQueues;
using HamcoWcs.Models.DeviceMsgs;
using HamcoWcs.Models.Devices;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace HamcoWcs.Workers
{
    public partial class PconWorker
    {
        private void DealGlobalConfigSend(PconPlc plc)
        {
            if (GlobalValue.PconGlobalConfigs.Values.Any(x => x.IsChange))
            {
                foreach (var cfg in GlobalValue.PconGlobalConfigs.Values)
                {
                    if (!cfg.IsChange) continue;
                    if (string.IsNullOrEmpty(cfg.NewValue))
                    {
                        _logger.AddSystemErrorLog($"PconWorker->DealGlobalConfigSend:{cfg.Name},类型{cfg.Type}，处理失败:新值为空");
                    }


                    if (cfg.Type == "INT")
                    {
                        UInt16 v = UInt16.Parse(cfg.NewValue);
                        var b = BitConverter.GetBytes(v).Reverse().ToArray();
                        var db = plc.DbInfo.FirstOrDefault(x => x.DbName == "other_send");
                        var res = plc.Client.DBWrite(db.DbNum, cfg.Offset, cfg.Length, b);
                        if (res != 0)
                        {
                            _logger.AddSystemErrorLog($"PconWorker->DealGlobalConfigSend:{cfg.Name},类型{cfg.Type}，处理失败:写入DB失败");

                        }
                    }
                    else
                    {
                        _logger.AddSystemErrorLog($"PconWorker->DealGlobalConfigSend:{cfg.Name},类型{cfg.Type}，处理失败：无当前类型的处理方法");
                    }
                    cfg.IsChange = false;
                }
            }
        }

        private void DealMaterialSend(PconPlc pconPlc)
        {
            if (MATERIAL_SEND_BUFFERS.Count > 0 && pconPlc.ConnectionStatus)
            {
                while (MATERIAL_SEND_BUFFERS.Count > 0)
                {
                    var info = MATERIAL_SEND_BUFFERS.Dequeue();

                    byte[] recvBuff = new byte[GlobalValue.CV_SEND_MSG_SIZE];
                    pconPlc.Client.DBRead(102, info.SendStartPoint, GlobalValue.CV_SEND_MSG_SIZE, recvBuff);
                    var msg = new PconSendMsg(recvBuff);

                    if (msg.Number != msg.Response) continue;

                    ushort number = (ushort)((msg.Number == ushort.MaxValue) ? 0 : msg.Number + 1);
                    info.Msg.Number = number;

                    var content = Encoding.ASCII.GetBytes(info.MaterialStr.PadRight(info.MaterialLength, ' '));
                    var res = pconPlc.Client.DBWrite(104, info.MaterialSendPoint, 100, content) == 0;

                    if (res)
                    {
                        pconPlc.Client.DBWrite(102, info.SendStartPoint, GlobalValue.CV_SEND_MSG_SIZE, info.Msg.Encode());
                        _logger.AddWcsRunLog("Material", $"下发{msg.PconName}物料信息{info.MaterialStr}成功");
                    }
                    else
                    {
                        MATERIAL_SEND_BUFFERS.Enqueue(info);
                        _logger.AddWcsRunLog("Material", $"下发{msg.PconName}物料信息{info.MaterialStr}失败");

                    }


                }
            }
        }

        private void DealRasterSend(PconPlc pconPlc)
        {
            if (RASTER_SEND_BUFFERS.Count > 0 && pconPlc.ConnectionStatus)
            {
                while (RASTER_SEND_BUFFERS.Count > 0)
                {
                    var info = RASTER_SEND_BUFFERS.Dequeue();
                    bool result;

                    if (info.SetRasterStatus)
                    {
                        result = info.Raster.ResetBypass(pconPlc.Client);
                    }
                    else
                    {
                        result = info.Raster.SetBypass(pconPlc.Client);
                    }

                    var content = info.SetRasterStatus ? "解除屏蔽光栅" : "屏蔽光栅";
                    var res = result ? "成功" : "失败";
                    var msg = $"{info.UserName}{content}{info.Raster.Name}，{res}";

                    _logger.AddWcsRunLog("raster", msg);
                }
            }
        }



        private void DealSend(PconPlc plc)
        {
            DealSendPcon(plc);
            DealMaterialSend(plc);
            DealRasterSend(plc);
            DealGlobalConfigSend(plc);

            SetPlcTime(plc);
        }

        /// <summary>
        /// 设置PLC时间(年月日时分秒)<br/>  DB:104,offset:20,length:12  
        /// </summary>
        /// <param name="plc"></param>
        private void SetPlcTime(PconPlc plc)
        {
            // 每小时写入PLC时间
            GlobalValue.SetPLCDateTimeTick++;
            if (GlobalValue.SetPLCDateTimeTick >= GlobalValue.SetPLCDateTimeInterval)
            {
                GlobalValue.SetPLCDateTimeTick = 0;

                var n = DateTime.Now;
                ushort y = (ushort)n.Year;
                byte M = (byte)n.Month;
                byte d = (byte)n.Day;
                byte h = (byte)n.Hour;
                byte m = (byte)n.Minute;
                byte s = (byte)n.Second;
                List<byte> t = new List<byte>(BitConverter.GetBytes(y).Reverse())
                {
                    0,M,0,d,0,h,0,m,0,s,
                };

                var b = t.ToArray();
                var res = plc.Client.DBWrite(104, 20, 12, b);

                if (res != 0)
                {
                    GlobalValue.SetPLCDateTimeTick = 3540;
                    _logger.AddWcsRunLog("settimeerror", $"设置{plc.PlcName}时间失败,1min后重试");
                }
                else
                {
                    //_logger.AddWcsRunLog("time", $"设置{plc.PlcName}时间为{n:yyyy-MM-dd HH:mm:ss}");
                }
            }
        }

        private void DealSendPcon(PconPlc pconPlc)
        {
            //检查连接状态
            if (!pconPlc.ConnectionStatus) return;
            //获取DB对象
            var dbInfo = pconPlc.DbInfo.FirstOrDefault(x => x.DbName == "send");
            //获取失败返回
            if (dbInfo == null) return;
            //获取数据库中的所有消息
            var msgs = _wcsDbContext.DeviceMsgQueues
                                    .Where(x => x.PlcName == pconPlc.PlcName)
                                    .OrderByDescending(x => x.CreatedTime)
                                    .ToList();
            //检查消息是否为空
            if (msgs == null || msgs.Count == 0) return;
            var msgQueueDtos = _mapper.Map<List<DeviceMsgQueueDto>>(msgs);

            try
            {
                foreach (var msgQueueDto in msgQueueDtos)
                {
                    //读取DB块，检查上次request是否处理完成
                    byte[] recvBuff = new byte[GlobalValue.CV_SEND_MSG_SIZE];
                    pconPlc.Client.DBRead(dbInfo.DbNum, msgQueueDto.StartPoint, GlobalValue.CV_SEND_MSG_SIZE, recvBuff);
                    var msg = new PconSendMsg(recvBuff);

                    // 获取要发生的设备,如果不为RUN则不发送
                    //var pcon = _asrs.Pcons.FirstOrDefault(x => x.PconName == msg.PconName);
                    var pcon = pconPlc.Pcons.Values.FirstOrDefault(x => x.PconName == int.Parse(msgQueueDto.DeviceName));


                    // [20230626][Obsolete]PLC未处理则跳过
                    //if (msg.Request != 0) continue;
                    // [20230626] 新增response number 若number=response则下发新任务
                    if (msg.Number != msg.Response) continue;
                    ushort number = (ushort)((msg.Number == ushort.MaxValue) ? 1 : msg.Number + 1);

                    //上次处理完成，直接写入DB块。
                    var sendmsgDto = JsonConvert.DeserializeObject<PconSendMsg>(msgQueueDto.MsgValue);

                    // 只有运行状态会下发任务,9999为全局控制块
                    if (pcon.PconName != 9999 && !pcon.Machine.IsRunning && sendmsgDto.Request == 1) continue;



                    sendmsgDto.Number = number;

                    byte[] sendMsg = sendmsgDto.Encode();
                    if (sendMsg.Length != GlobalValue.CV_SEND_MSG_SIZE) return;



                    var res = pconPlc.Client.DBWrite(dbInfo.DbNum, msgQueueDto.StartPoint, GlobalValue.CV_SEND_MSG_SIZE, sendMsg);
                    if (res != 0) throw new Exception($"DealSend:发送不成功 ErrorCode {res}");

                    pconPlc.Client.DBRead(dbInfo.DbNum, msgQueueDto.StartPoint, GlobalValue.CV_SEND_MSG_SIZE, recvBuff);
                    var checkmsg = new PconSendMsg(recvBuff);
                    if (checkmsg.Number == number)
                    {
                        var msgEntity = msgs.FirstOrDefault(x => x.Id == msgQueueDto.Id);
                        _wcsDbContext.DeviceMsgQueues.Remove(msgEntity);
                        Thread.Sleep(50);
                        var result = _wcsDbContext.SaveChanges();
                    }

                    _communicationLogs.Add(new CommunicationLog("WCS >> PCON")
                    {
                        TransactionId = $"{DateTime.Now:yyyyMMddHHmmssffffff}",
                        Sender = "WCS",
                        Receiver = pcon.DeviceName,
                        Content = msgQueueDto.MsgValue,
                        MessageName = ((EnumPconSendMsg)sendmsgDto.Request).ToString(),
                        MessageStatus = $"number:{number}",
                        MessageType = "",
                        Return = "",
                        UnitId = sendmsgDto.UnitId,
                        CreatedTime = DateTime.Now,
                    });
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
    }
}
